<?php
ini_set("display_errors", true);
error_reporting(E_ALL);

require_once('../simpletest/autorun.php');
require_once('../../src/v1/scottlib-test.php');

// NOTE: this file is not in the repository, as it contains my personal AWS keys
require_once('aws_config.php');

class TestBigtables extends UnitTestCase {

	private $domainCreated = false;
	
	function setUp() {
		global $aws_key, $aws_secret_key;
		bigtable($aws_key, $aws_secret_key, true);
		
		if (!$this->domainCreated && !bigtable()->domain_exists()) {
			bigtable()->create_domain();
			$this->domainCreated = true;
		}
	}
	
	function testBigtableWithArrayArguments() {
		bigtable(array(
			'host' => ':/tmp/mysql.sock',
			'user' => 'root',
			'pass' => 'password',
			'db' => 'mysql',
			'engine' => 'slMySqlBigtableEngine'
		));
		
		$this->assertEqual('slMySqlBigtableEngine', get_class(bigtable()));
	}
	
	function testNumericTestFunctions() {
		$this->assertTrue(is_numeric(-1));
		$this->assertTrue(is_numeric(0));
		$this->assertTrue(is_numeric(1));
		$this->assertTrue(is_numeric(3.1415));
		$this->assertTrue(is_numeric("1"));
		$this->assertTrue(is_numeric("3.1415"));
		$this->assertFalse(is_numeric('$1.25'));
	}
	
	function testDataClass() {
		
		$obj = new stdClass();
		$obj->foo = "string";
		$obj->bar = 3.1415;
		
		$now = time();
		
		$data = data(array(
			"int" => 5,
			"float" => 3.1415,
			"string" => "Hello, world!",
			"object" => $obj,
			"date" => date("Y/m/d H:i:s", $now),
			"array" => array('one', 'two', 'three')
		));
		
		$this->assertEqual($data->int, 5);
		$this->assertEqual($data->float, 3.1415);
		$this->assertEqual($data->string, "Hello, world!");
		$this->assertEqual($data->object, $obj);
		$this->assertEqual(strtotime($data->date), $now);
		$this->assertEqual($data->array, array('one', 'two', 'three'));
		
	}
	
	function testPadding() {
		$data = new slData('default');
		
		// floats:
		$val = 3.1415;
		$data->float_sorted = $val;
		$this->assertEqual($data->float, round($val, SL_BIGTABLES_DECIMAL_PRECISION)+abs(SL_BIGTABLES_NUMERIC_MIN));
		$this->assertEqual($data->float_sorted, round($val, SL_BIGTABLES_DECIMAL_PRECISION));
		
		// integers:
		$val = 123456789;
		$data->int_sorted = $val;
		$this->assertEqual($data->int, $val+abs(SL_BIGTABLES_NUMERIC_MIN));
		$this->assertEqual($data->int_sorted, $val);
		
		// dates:
		$val = '10/26/1981 3:50 PM';
		$data->date_sorted = $val;
		$this->assertEqual(strtotime($val), strtotime($data->date_sorted));
		$this->assertEqual(strtotime($val), strtotime($data->date));
	}
	
	function testEngineReadWrite() {
		
		$obj = new stdClass();
		$obj->foo = "string";
		$obj->bar = 3.1415;
		
		$now = time();
		
		$data = data(array(
			"int" => 5,
			"float" => 3.1415,
			"string" => "Hello, world!",
			"object" => $obj,
			"date" => date("Y/m/d H:i:s", $now),
			"array" => array('one', 'two', 'three')
		));
		
		$data->save();
		
		$read = $this->tryGetUntil($data->itemName, 10);
		
		$this->assertEqual($data->int, $read->int);
		$this->assertEqual($data->float, $read->float);
		$this->assertEqual($data->string, $read->string);
		$this->assertEqual(strtotime($data->date), strtotime($read->date));
		
		$data = new slData();
		$data->int_sorted = 5;
		$data->float_sorted = 3.1415;
		$data->string_sorted = "Hello, world!";
		$data->object_sorted = $obj;
		$data->date_sorted = date("Y/m/d/H:i:s", $now);
		$data->array_sorted = array('one', 'two', 'three');
		$data->save();
		
		$read = $this->tryGetUntil($data->itemName, 10);
		
		$this->assertEqual($data->int_sorted, $read->int_sorted);
		$this->assertEqual($data->float_sorted, $read->float_sorted);
		$this->assertEqual($data->string_sorted, $read->string_sorted);
		$this->assertEqual(strtotime($data->date_sorted), strtotime($read->date_sorted));
			
		// TODO: mysql
		
	}
	
	private function tryGetUntil($itemName, $seconds) {
		$wait_time = 0;
		
		while((($read = bigtable()->get($itemName)) == null) && $wait_time < $seconds) {
			sleep(1);
			$wait_time++;
		}
		
		$this->assertFalse($wait_time == $seconds && !$read, "Failed to read Item saved $itemName");
			
		return $read;
	}
	
	private function tryDeleteUntil($itemName, $seconds) {
		// first, delete the record
		bigtable()->delete($itemName);
		
		$itemName = ($itemName instanceof slData ? $itemName->itemName : $itemName);
		
		$wait_time = 0;
		
		while (($read = bigtable()->get($itemName)) != null) {
			sleep(1);
			$wait_time++;
		}
		
		$this->assertFalse($wait_time == $seconds && $read != null, "Failed to delete Item $itemName");
	}
	
	function testEngineDelete() {
		
		// create some data
		$data = data_save(array('name' => 'Karla Valverde Collegeman'));
		
		// wait for it to be readable
		$read = $this->tryGetUntil($data->itemName, 10);
		
		$this->assertEqual($data->name, $read->name);
		
		// delete it
		$this->tryDeleteUntil($read->itemName, 10);
		
		// create some more data
		$data = data_save(array('name' => 'Aaron Collegeman'));
		
		// wait for it to be readable
		$read = $this->tryGetUntil($data->itemName, 10);
		
		$this->assertEqual($data->name, $read->name);
		
		// delete it
		$this->tryDeleteUntil($read, 10);
		
		// TODO: mysql
	}
	
	
	private function tryToReadAttributeUntil($itemName, $key, $value, $seconds) {
		
		$read = null;
		$wait_time = 0;
		
		do {
			sleep(1);
			$stored = bigtable()->get($itemName);
			$read = $stored->$key;
			$wait_time++;
		} while ($read != $value && $wait_time < $seconds);
		
		$this->assertEqual($value, $read, "$itemName".'->'."$key never equaled '".print_r($value, true)."': actual '".print_r($read, true)."'");
		
	}
	
	function testReplacement() {
		
		// save some data
		$data = data_save(array('favorites' => array('red', 'blue')));
		
		// now do a replacement
		$data->favorites = replacement('green');
		$data->save();
		
		// ensure that the data reads only the replacement
		$this->tryToReadAttributeUntil($data->itemName, 'favorites', 'green', 10);
		
		bigtable()->delete($data->itemName);
	
	}
	
	private function tryQueryUntil($expectedResultCount, $seconds, slCriteria $criteria) {
		
		$wait_time = 0;
		
		while (!count($list = bigtable()->query($criteria))) {
			$wait_time++;
			sleep(1);
		}
		
		$this->assertFalse($wait_time == $seconds && count($list) != $expectedResultCount, "Failed to query expected number of results; $expectedResultCount");
		
	}
	
	function testSelect()  {
		eval(slCriteria::import());
		
		// save some data
		$items = array();
		$items[] = data_save(array('color' => 'red'));
		$items[] = data_save(array('color' => array('red', 'blue')));
		$items[] = data_save(array('color' => 'blue'));
		$items[] = data_save(array('color' => 'blue', 'orange'));
		
		//$this->tryQueryUntil(1, 10, $eq('color', 'red'));
		
		
		
		// delete the data
		foreach($items as $item)
			bigtable()->delete($item);
		
		
		// TODO: bigtable()->attrs($criteria)
			
			
		// TODO: bigtable()->query($criteria);
			
	}
	
	
}
